from common.mongodb import MongoDB
from flask_restful import Resource, fields, reqparse, abort, marshal


class Metro(Resource):
    todos = ['root', 'city', 'line']

    city_py_list = {
        '1100': 'beijing',
        '3100': 'shanghai',
        '4401': 'guangzhou',
        '4403': 'shenzhen',
        '4201': 'wuhan',
        '1200': 'tianjin',
        '3201': 'nanjing',
        '8100': 'xianggang',
        '5000': 'chongqing',
        '3301': 'hangzhou',
        '2101': 'shenyang',
        '2102': 'dalian',
        '5101': 'chengdu',
        '2201': 'changchun',
        '3205': 'suzhou',
        '4406': 'foshan',
        '5301': 'kunming',
        '6101': 'xian',
        '4101': 'zhengzhou',
        '4301': 'changsha',
        '3302': 'ningbo',
        '3202': 'wuxi',
        '3702': 'qingdao',
        '3601': 'nanchang',
        '3501': 'fuzhou',
        '4419': 'dongguan',
        '4501': 'nanning',
        '3401': 'hefei',
        '5201': 'guiyang',
        '3502': 'xiamen',
        '2301': 'haerbin',
        '1301': 'shijiazhuang'
    }
    # 根信息响应
    root_fields = {
        # 响应码
        'errorCode': fields.String,
        # 响应信息
        'message': fields.String,
        # 当前城市码
        'cur_city_code': fields.String,
        # 当前城市名
        'cur_city_name': fields.String,
        # 附近站点
        'n_station': fields.Nested({
            # 站点号
            's_code': fields.String,
            # 站点名
            's_name': fields.String,
            # 该站点可乘地铁
            'tr_list': fields.List(fields.String)
        }),
        # 城市列表
        'c_list': fields.List(
            fields.Nested({
                # 城市号
                'c_code': fields.String,
                # 城市名
                'c_name': fields.String,
                # 城市名拼音
                'c_py': fields.String
            })
        )
    }

    # 城市信息响应
    city_fields = {
        # 响应码
        'errorCode': fields.String,
        # 响应信息
        'message': fields.String,
        # 车城市号
        'c_code': fields.String,
        # 城市名
        'c_name': fields.String,
        # 城市经度
        'c_long': fields.String,
        # 城市维度
        'c_lat': fields.String,
        # 线路列表
        'l_list': fields.List(
            fields.Nested({
                # 线路号
                'l_code': fields.String,
                # 线路名
                'l_name': fields.String,
                # 线路背景色
                'l_color': fields.String,
                # 是否启用
                'is_a': fields.String
            })
        )
    }

    # 线路信息响应
    line_fields = {
        # 响应码
        'errorCode': fields.String,
        # 响应信息
        'message': fields.String,
        # 线路号
        'l_code': fields.String,
        # 线路名
        'l_name': fields.String,
        # 启用
        'is_a': fields.String,
        # 线路端点信息（可以从线路站点列表取首尾得到
        'l_ter': fields.List(
            fields.Nested({
                # 端点站号
                's_code': fields.String,
                # 端点站名
                's_name': fields.String
            })
        ),
        # 两个方向
        'l_dir': fields.List(
            fields.List(
                fields.Nested({
                    # 站点号
                    's_code': fields.String,
                    # 站点名
                    's_name': fields.String,
                    # 首末班车时间
                    't_ft': fields.String,
                    't_lt': fields.String,
                    # 换乘
                    'tr_list': fields.List(
                        fields.Nested({
                            'l_code': fields.String,
                            'l_name': fields.String,
                            'l_color': fields.String
                        })
                    )
                })
            )
        )
    }

    def abort_if_todo_doesnt_exist(self, todo):
        if todo not in self.todos:
            abort(404, message="Todo {} doesn't exist".format(todo))

    def get(self, todo):
        self.abort_if_todo_doesnt_exist(todo)
        return None

    def post(self, todo):
        self.abort_if_todo_doesnt_exist(todo)
        parser = reqparse.RequestParser()
        # todo 根节点的请求
        if todo == self.todos[0]:
            parser.add_argument('long', type=str)
            parser.add_argument('lat', type=str)
            parser.add_argument('c_name', type=str)
            args = parser.parse_args()
            long = args['long']
            lat = args['lat']
            c_name = args['c_name']

            if c_name is None or c_name == '':
                c_name = '上海'
            if long is None or long == '':
                long = 121.32
            if lat is None or lat == '':
                lat = 31.20

            min_discante = 180.0 ** 2 + 90 ** 2
            mongo = MongoDB("metro")
            db_list = mongo.find_many('metro')
            cur_city_code = ''
            cur_city_name = ''
            n_station = {}
            c_list = []
            for c_item in db_list:
                c_list.append({
                    'c_code': c_item['c_code'],
                    'c_name': c_item['c_name'],
                    'c_py': self.city_py_list[c_item['c_code']]
                })
                if c_item['c_name'].find(c_name) > -1:
                    cur_city_code = c_item['c_code']
                    cur_city_name = c_item['c_name']
                    for s_item in c_item['s_info'].values():
                        temp_distance = (float(s_item['long']) - float(long)) ** 2 + (
                                float(s_item['lat']) - float(lat)) ** 2
                        if temp_distance < min_discante:
                            min_discante = temp_distance
                            n_station = {
                                's_code': s_item['s_code'],
                                's_name': s_item['s_name'],
                                'tr_list': list((map(lambda l_code: c_item['l_info'][l_code]['l_name'], filter(lambda l_code:l_code != '900000113361',s_item['s_trans']))))
                            }
            return marshal(
                dict(errorCode=0, message='', cur_city_code=cur_city_code, cur_city_name=cur_city_name,
                     n_station=n_station, c_list=c_list),
                self.root_fields)

        # todo city请求
        elif todo == self.todos[1]:
            parser.add_argument('c_code', type=str)
            args = parser.parse_args()
            c_code = args['c_code']
            if c_code is None or c_code == '':
                c_code = '3100'
            mongo = MongoDB("metro")
            db_item = mongo.find_one('metro', c_code=c_code)
            c_name = db_item['c_name']
            l_list = []
            c_long = 0
            c_lat = 0
            for l_item in db_item['l_info'].values():
                l_list.append({
                    'l_code': l_item['l_code'],
                    'l_name': l_item['l_name'],
                    'l_color': l_item['l_color'],
                    'is_a': l_item['is_available']
                })
            long_list = [float(item['long']) for item in db_item['s_info'].values()]
            lat_list = [float(item['lat']) for item in db_item['s_info'].values()]
            c_long = sum(long_list) / len(long_list)
            c_lat = sum(lat_list) / len(lat_list)
            return marshal(dict(errorCode='0', message='', c_code=c_code, c_name=c_name, c_long=c_long, c_lat=c_lat,
                                l_list=l_list),
                           self.city_fields)

        # todo line 请求
        elif todo == self.todos[2]:
            # 参数转换
            parser.add_argument('c_code', type=str)
            parser.add_argument('l_code', type=str)
            args = parser.parse_args()
            c_code = args['c_code']
            l_code = args['l_code']
            # 准备返回的key
            l_name = ''
            is_a = ''
            l_ter = []
            l_dir = [[], []]

            # 参数为空设定默认值
            if c_code is None or c_code == '':
                c_code = '3100'
            if l_code is None or l_code == '':
                l_code = '310100025685'

            # 获取数据库连接
            mongo = MongoDB("metro")
            db_item = mongo.find_one('metro', c_code=c_code)
            # 遍历该市的线路信息
            for l_item in db_item['l_list']:
                # 处理目标线路
                if l_item['l_code'] == l_code:
                    # 线路名称
                    l_name = l_item['l_name']
                    # 线路可用
                    is_a = l_item['is_available']
                    # 线路首尾站点
                    l_ter = [l_item['s_list'][0], l_item['s_list'][-1]]
                    # 两个方向的车子 分别处理。然后其中一个做逆序处理
                    for index, s_item in enumerate(l_item['s_list']):
                        lenth = len(l_item['s_list'])
                        t_lt_up, t_ft_up, t_lt_down, t_ft_down = '--:--', '--:--', '--:--', '--:--'
                        # 高德地图上海12号线有bug，临时处理
                        if l_code == '310100025711':
                            # 金海路，嘉善路单独处理
                            if s_item['s_code'] in ['310100024546033', '310100024546020']:
                                t_ft_up = s_item['t_dict'][l_item['s_list'][0]['s_code']]['ft']
                                t_lt_up = s_item['t_dict'][l_item['s_list'][0]['s_code']]['lt']
                            else:
                                t_ft_up = s_item['t_dict'][l_item['s_list'][0]['s_code']]['ft']
                                t_lt_up = s_item['t_dict'][l_item['s_list'][0]['s_code']]['lt']
                                t_ft_down = s_item['t_dict']['310100025711002']['ft']
                                t_lt_down = s_item['t_dict']['310100025711002']['lt']
                        else:
                            # 环线需要单独处理
                            if l_item['is_loop'] == '1':
                                if s_item['t_dict'].__contains__(l_item['s_list'][(index + 1) % lenth]['s_code']):
                                    t_ft_up = s_item['t_dict'][l_item['s_list'][(index + 1) % lenth]['s_code']]['ft']
                                    t_lt_up = s_item['t_dict'][l_item['s_list'][(index + 1) % lenth]['s_code']]['lt']
                                if s_item['t_dict'].__contains__(l_item['s_list'][(index - 1) % lenth]['s_code']):
                                    t_ft_down = s_item['t_dict'][l_item['s_list'][index - 1]['s_code']]['ft']
                                    t_lt_down = s_item['t_dict'][l_item['s_list'][index - 1]['s_code']]['lt']
                            else:
                                for t_key in s_item['t_dict']:
                                    if t_key in [item['s_code'] for item in l_item['s_list'][index:]]:
                                        t_ft_up = s_item['t_dict'][t_key]['ft']
                                        t_lt_up = s_item['t_dict'][t_key]['lt']
                                    elif t_key in [item['s_code'] for item in l_item['s_list'][:index + 1]]:
                                        t_ft_down = s_item['t_dict'][t_key]['ft']
                                        t_lt_down = s_item['t_dict'][t_key]['lt']
                        up_dict = {
                            's_code': s_item['s_code'],
                            's_name': s_item['s_name'],
                            't_ft': t_ft_up,
                            't_lt': t_lt_up,
                            'tr_list':
                                list(
                                    filter(
                                        lambda x: x['l_code'] != l_code,
                                        map(
                                            lambda i: dict(l_code=s_item['s_trans_code'][i],
                                                           l_name=s_item['s_trans_name'][i],
                                                           l_color=s_item['s_trans_color'][i]),
                                            range(0, len(s_item['s_trans_code']))
                                        )
                                    )
                                )
                        }
                        down_dict = {
                            's_code': s_item['s_code'],
                            's_name': s_item['s_name'],
                            't_ft': t_ft_down,
                            't_lt': t_lt_down,
                            'tr_list':
                                list(
                                    filter(
                                        lambda x: x['l_code'] != l_code,
                                        map(
                                            lambda i: dict(l_code=s_item['s_trans_code'][i],
                                                           l_name=s_item['s_trans_name'][i],
                                                           l_color=s_item['s_trans_color'][i]),
                                            range(0, len(s_item['s_trans_code']))
                                        )
                                    )
                                )
                        }
                        l_dir[0].append(up_dict)
                        l_dir[1].append(down_dict)
            l_dir[1].reverse()
        return marshal(
            dict(errorCode='0', message='', l_code=l_code, l_name=l_name, is_a=is_a, l_ter=l_ter,
                 l_dir=l_dir), self.line_fields)
